/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.minidota.model;

import com.minidota.constant.Constant;
import com.minidota.jsonmodels.JsonUnitInfo;
import com.minidota.game.Room;
import com.minidota.impl.HeroesImpl;
import com.minidota.jetty.GameWebSocket;
import com.minidota.utils.Util;
import java.util.ArrayList;

/**
 *
 * @author custom
 */
public class Tower extends BaseObject {
    //private long id;

    private int id;
    private int command;//команда которую выполняет обьект
    private int animation; //0 дышит, 2 - атака 
    private BaseObject target;//цель которую преследует обьект
    private long lastAtackTick;// тик в котором была нанесена последняя атака
    private double ticksAddBetweanAttack;//остаток между тиками наращивается для тонкой настройки скорости атаки
    private int type;
    private int maxHP;
    private int damage;
    private ArrayList<Tower> prevTowers;

    public Tower(Room room, int teamId, Vector2 position, int type, int damage, ArrayList<Tower> prevTowers) {
        setRoom(room);
        this.setPosition(position);
        this.setTeamId(teamId);
        setGameId(getRoom().getFreeGameId());
        setType(type);
        if (getType() == 0) {
            setHP(3000);
            setMaxHP(3000);
            setRadius(100);
        } else {
            setHP(1300);
            setMaxHP(1300);
            setRadius(50);
        }
        setDamage(damage);
        setPrevTowers(prevTowers);
    }

    public Object getJsonData() {
        JsonUnitInfo jui = new JsonUnitInfo();
        jui.setId(getId());
        jui.setGameId(getGameId());
        jui.setTeamId(getTeamId());
        return jui;
    }

    public String getExtendedData() {
        StringBuilder sb = new StringBuilder();
        sb.append(Util.getCharByCode(getGameId()));
        sb.append(Util.getCharByCode(getDamage()));
        sb.append(Util.getCharByCode(getArmor()));
        sb.append(Util.getCharByCode((int) (getHP() < 0 ? 0 : getHP())));
        sb.append(Util.getCharByCode(getMaxHP()));
        sb.append(Util.getCharByCode(0));
        sb.append(Util.getCharByCode(0));
        return sb.toString();
    }

    @Override
    public void updateData(long tick) {
        super.updateData(tick);
        if (isAlive()) {
            if (getDamage() > 0) {
                if (getTarget() != null) {
                    setViewAngle(getTarget().getPosition().sub(getPosition()).calcVector2Angle());
                    if (tick - getLastAtackTick() < getTicksForAnimationAttack()) {
                        if (tick == getLastAtackTick() + Math.round(2 * getTicksForAnimationAttack() / 3)) {
                            new Arrow(this, getTarget(), 0, 0).init();
                        }
                    }
                    if (getPosition().sub(getTarget().getPosition()).lengthSquared() < Math.pow(getTarget().getRadius() + getRadius() + getAtackRadius(), 2)) {
                        if (tick - getLastAtackTick() >= getTicksForAnimationAttack() && tick - getLastAtackTick() >= Math.floor(getTicksBetweanAttack() + getTicksAddBetweanAttack())) {
                            setTicksAddBetweanAttack((getTicksBetweanAttack() + getTicksAddBetweanAttack()) % Math.floor(getTicksBetweanAttack() + getTicksAddBetweanAttack()));
                            setLastAtackTick(tick);
                            setAnimation(2);
                        } else {
                            setAnimation(0);
                        }
                    } else {
                        setTarget(null);
                        setAnimation(0);
                    }
                } else {
                    for (User u : getRoom().getUsers()) {
                        if (getPosition().sub(u.getPosition()).lengthSquared() < Math.pow(u.getRadius() + getRadius() + getAtackRadius(), 2) && u.getTeamId() != getTeamId() && u.isAlive()) {
                            setTarget(u);
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * @return возвращает данные об объекте клиенту
     */
    @Override
    public String getSendData() {
        StringBuilder sb = new StringBuilder();
        sb.append(Util.getCharByCode(getGameId()));
        sb.append(Util.getCharByCode((int) Math.round(getPosition().getX() * 5)));
        sb.append(Util.getCharByCode((int) Math.round(getPosition().getY() * 5)));
        sb.append(Util.getCharByCode((int) Math.round(getAnimation())));
        sb.append(Util.getCharByCode(getViewAngle()));
        sb.append(Util.getCharByCode((int) (getHP() < 0 ? 0 : getHP())));
        sb.append(Util.getCharByCode(getMaxHP()));
        sb.append(Util.getCharByCode(getTeamId()));
        if (getTeamId() == 1) {
            sb.append(Util.getCharByCode(getType()));
        } else {
            sb.append(Util.getCharByCode(getType() + 10));
        }
        return sb.toString();
    }

    public void init() {
        getRoom().getTowers().add(this);
    }

    public int getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return the lastAtackTick
     */
    public long getLastAtackTick() {
        return lastAtackTick;
    }

    /**
     * @param lastAtackTick the lastAtackTick to set
     */
    public void setLastAtackTick(long lastAtackTick) {
        this.lastAtackTick = lastAtackTick;
    }

    /**
     * @return the atackRadius
     */
    public int getAtackRadius() {
        return 420;
    }

    /**
     * @return the command
     */
    public int getCommand() {
        return command;
    }

    /**
     * @param command the command to set
     */
    public void setCommand(int command) {
        this.command = command;
    }

    /**
     * @return the animation
     */
    public int getAnimation() {
        return animation;
    }

    /**
     * @param animation the animation to set
     */
    public void setAnimation(int animation) {
        this.animation = animation;
    }

    /**
     * @return the armor
     */
    public int getArmor() {
        return (int) (10);
    }

    /**
     * @return the damage
     */
    public int getDamage() {
        return damage;
    }

    /**
     * @return the ticksBetweanAttack
     */
    public double getTicksBetweanAttack() {
        double tmpTickBAtack = 5;
        return tmpTickBAtack < 4 ? 4 : tmpTickBAtack;
    }

    /**
     * @return the ticksAddBetweanAttack
     */
    public double getTicksAddBetweanAttack() {
        return ticksAddBetweanAttack;
    }

    /**
     * @param ticksAddBetweanAttack the ticksAddBetweanAttack to set
     */
    public void setTicksAddBetweanAttack(double ticksAddBetweanAttack) {
        this.ticksAddBetweanAttack = ticksAddBetweanAttack;
    }

    public int getTicksForAnimationAttack() {
        return (int) Math.round(getTicksBetweanAttack() / 2);
    }

    @Override
    public void doDamage(BaseObject attacker, double damage) {
        if (attacker.isAlive() && getTarget() == null) {
            setTarget(attacker);
        }
        boolean isPosible = true;
        if (getPrevTowers() != null) {
            if (getType() == 2) {
                isPosible = false;
                for (Tower t : getPrevTowers()) {
                    if (!t.isAlive()) {
                        isPosible = true;
                        break;
                    }
                }
            } else {
                for (Tower t : getPrevTowers()) {
                    if (t.isAlive()) {
                        isPosible = false;
                        break;
                    }
                }
            }
        }
        if (isPosible) {
            addHP(-damage);
            if (!isAlive()) {
                calcKill();
            }
        }
    }

    public void deleteMeFromTargets() {
        for (User u : getRoom().getUsers()) {
            if (u.getTarget() != null && u.getTarget().getGameId() == getGameId()) {
                u.setTarget(null);
            }
        }
        for (Tower t : getRoom().getTowers()) {
            if (t.getTarget() != null && t.getTarget().getGameId() == getGameId()) {
                t.setTarget(null);
            }
        }
    }

    private void calcKill() {
        deleteMeFromTargets();
        setCommand(0);
        if (getType() == 0) {
            getRoom().setTickToEndRound(25);
            for (User u : getRoom().getUsers()) {
                if (u instanceof Player) {
                    if (u.getTeamId() == getTeamId()) {
                        u.getSocket().sendMsg("rml");//проиграли
                    } else {
                        u.getSocket().sendMsg("rmv");// победили
                    }
                }
            }
        }
        /*ArrayList<User> users = getUserCollisionExp();
         for (User u : users) {
         u.addExp((int) (exp / users.size()));
         }*/
    }

    /**
     * @param maxHP the maxHP to set
     */
    public void setMaxHP(int maxHP) {
        this.maxHP = maxHP;
    }

    /**
     * @return the maxHP
     */
    public int getMaxHP() {
        return maxHP;
    }

    /**
     * @param damage the damage to set
     */
    public void setDamage(int damage) {
        this.damage = damage;
    }

    /**
     * @return the target
     */
    public BaseObject getTarget() {
        return target;
    }

    /**
     * @param target the target to set
     */
    public void setTarget(BaseObject target) {
        this.target = target;
    }

    /**
     * @return the type
     */
    public int getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(int type) {
        this.type = type;
    }

    /**
     * @return the prevTowers
     */
    public ArrayList<Tower> getPrevTowers() {
        return prevTowers;
    }

    /**
     * @param prevTowers the prevTowers to set
     */
    public void setPrevTowers(ArrayList<Tower> prevTowers) {
        this.prevTowers = prevTowers;
    }

}
